import sys

import svm
import svmutil
from svmutil import *

import os
import time

import mygrid
from multiprocessing import Pool
from scipy import *
from numpy import *
import matplotlib
#matplotlib.use("Agg")
#from pylab import *
from matplotlib.backends.backend_pdf import PdfPages


def load_data(fn):
	output = []
	
	numofcols = 0
	numofrows = 0
	for line in open(fn,'r').readlines():
		parts = line.rstrip().rsplit()
		numofcols = max(numofcols,int(parts[-1].rsplit(':')[0]))
		numofrows += 1
		
	input = zeros([numofrows,numofcols],dtype='float64')
	
	rowind = 0
	for line in open(fn,'r').readlines():
		parts = line.rstrip().rsplit()
		
		output.append(float(parts[0]))
		for keyval in parts[1:]:
			key,val = keyval.rsplit(':')
			input[rowind,int(key)-1] = float(val)
		rowind += 1
		
	
	return output,input
		

class Timer():
   def __enter__(self): self.start = time.time()
   def __exit__(self, *args): print 'Entire Parameter Searching Experiment took %d seconds' % (time.time() - self.start)

   
     

def save_scale_data(fn,maxinput,mininput):
	finput = open(fn,'w')
	for ind in xrange(len(maxinput)):
		print >> finput, '%g, %g' % (mininput[ind],maxinput[ind])
	finput.close()

	 
def main(args):
	paramsfn = args[0]
	exec(open(paramsfn,'r').read())
	
	pdfpages = PdfPages('%s.pdf' % (outputlog))
	
	if len(args) > 1:
		crange = [float(args[1])]
		gammarange = [float(args[2])]
	
	output,input = load_data(datafilename)
	if testdatafilename != '':
		output_test,input_test = load_data(testdatafilename)
		
	if doscale:
		maxinput = input.max(0);
		mininput = input.min(0);
		input = (input-mininput)/(maxinput-mininput)
		
		if testdatafilename != '':
			input_test = (input_test-mininput)/(maxinput-mininput)

		if savemodel:
			save_scale_data(datafilename+'_scales.dat',maxinput,mininput)
			
	if numcpus == 'auto':
		p = Pool()
	else:
		p = Pool(numcpus)
	
	if choose_specific_features:
		for specific_selected_choice in specific_selected_features:
			inputfiltered = input[:,specific_selected_choice]
			
			with Timer():
				results = mygrid.grid_classify (crange,gammarange,output,[list(x) for x in inputfiltered],nf,useprob,timeout,p)				
				
			param = svm.svm_parameter('-c %g -g %g -b %d' % (results[-2],results[-1],int(useprob)))
			prob = svm.svm_problem(output, [list(x) for x in inputfiltered])
			target = (c_double * prob.l)()
			if posclass == 'auto':
				posclass = output[0]
			libsvm.svm_cross_validation(prob, param, nf, target)
			ys = prob.y[:prob.l]
			db = array([[ys[i],target[i]] for i in range(prob.l)])
			del target
			
			neg = len([x for x in ys if x != posclass])
			pos = prob.l-neg;
			auc,topacc,optbias,top_tps_bias,top_fps = mygrid.calc_AUC(db,neg,pos,posclass,[],True,pdfpages,'Optimal Cross-Validation ROC curve')
				
#			print results[:-1]
			print 'Optimal gamma = %g\nOptimal c = %g\nOptimal Bias = %g' % (results[-1],results[-2],results[-3])
			print 'Top CV results: AUC = %g, OPTIMIZED ACC = %g' % (auc,topacc)
			if savemodel:
				param = ('-c %g -g %g -b %d' % (results[-2],results[-1],int(useprob)))
				m = svm_train(output,[list(x) for x in inputfiltered],param)
				svm_save_model(datafilename + '.model',m)
				
				
			
			if testdatafilename != '':
				inputfiltered_test = input_test[:,specific_selected_choice]
				param = ('-c %g -g %g -b %d' % (results[-2],results[-1],int(useprob)))
				m = svm_train(output,[list(x) for x in inputfiltered],param)	
				pred_labels, (ACC, MSE, SCC), pred_values = svm_predict(output_test,[list(x) for x in inputfiltered_test],m,'-b %d' % (int(useprob)))
				ACC,confusionmatrix = mygrid.evaluations_classify(output_test, [x[0] for x in pred_values],posclass,results[-3])
				db = array([[output_test[i],pred_values[i][0]] for i in range(len(output_test))])
				neg = len([x for x in output_test if x != posclass])
				pos = len(output_test)-neg;

				if neg != 0 and pos != 0:
					auc,topacc,optbias,top_tps_bias,top_fps = mygrid.calc_AUC(db,neg,pos,posclass,[],True,pdfpages,'Test ROC curve')


				print 'Test optimized accuracy = %g' % (ACC)
				print '================================'
				print '||   ||%6d |%6d |       ||' % (m.get_labels()[0],m.get_labels()[1])
				print '================================'
				print '||%3d||%6g |%6g |%6g ||' % (m.get_labels()[0],confusionmatrix[0,0],confusionmatrix[0,1],pos)#confusionmatrix[0,0]+confusionmatrix[0,1])
				print '||%3d||%6g |%6g |%6g ||' % (m.get_labels()[1],confusionmatrix[1,0],confusionmatrix[1,1],neg)#confusionmatrix[1,0]+confusionmatrix[1,1])
				print '||----------------------------||'
				print '||   ||%6g |%6g |%6g ||' % (confusionmatrix[0,0]+confusionmatrix[1,0],confusionmatrix[0,1]+confusionmatrix[1,1],pos+neg)#confusionmatrix[1,0]+confusionmatrix[1,1])
				print '================================'

			
			if outputlog != '':
				fout = open(outputlog,'a')
				print >> fout, '========================='
				print >> fout, specific_selected_choice
				print >> fout, results#[:-1]
#				for key in results[-1].keys():
#					print >> fout, key, results[-1][key]
				fout.close()
	else:
		
		with Timer():
			results = mygrid.grid_classify (crange,gammarange,output,[list(x) for x in input],nf,useprob,timeout,p)

		param = svm.svm_parameter('-c %g -g %g -b %d' % (results[-2],results[-1],int(useprob)))
		prob = svm.svm_problem(output, [list(x) for x in input])
		target = (c_double * prob.l)()
		
		if posclass == 'auto':
			posclass = output[0]
			
		libsvm.svm_cross_validation(prob, param, nf, target)
		ys = prob.y[:prob.l]
		db = [[ys[i],target[i]] for i in range(prob.l)]
		db = array(db)
		neg = len([x for x in ys if x != posclass])
		pos = prob.l-neg;
		
		auc,topacc,optbias,top_tps_bias,top_fps = mygrid.calc_AUC(db,neg,pos,posclass,[],True,pdfpages,'Optimal Cross-Validation ROC curve')
		
		del target
		
		print 'Optimal gamma = %g\nOptimal c = %g\nOptimal Bias = %g' % (results[-1],results[-2],results[-3])
		print 'Top CV results: AUC = %g, OPTIMIZED ACC = %g' % (auc,topacc)
		if savemodel:
			param = ('-c %g -g %g -b %d' % (results[-2],results[-1],int(useprob)))
			m = svm_train(output,[list(x) for x in input],param)
			svm_save_model(datafilename+'.model',m)
		
		if testdatafilename != '':
			param = ('-c %g -g %g -b %d' % (results[-2],results[-1],int(useprob)))
			m = svm_train(output,[list(x) for x in input],param)

			pred_labels, (ACC, MSE, SCC), pred_values = svm_predict(output_test,[list(x) for x in input_test],m,'-b %d' % (int(useprob)))
			ACC,confusionmatrix = mygrid.evaluations_classify(output_test, [x[0] for x in pred_values],posclass,results[-3])

			db = array([[output_test[i],pred_values[i][0]] for i in range(len(output_test))])
			neg = len([x for x in output_test if x != posclass])
			pos = len(output_test)-neg;
			if neg != 0 and pos != 0:
				auc,topacc,optbias,top_tps_bias,top_fps = mygrid.calc_AUC(db,neg,pos,posclass,[],True,pdfpages,'Test ROC curve')

			print 'Test optimized accuracy = %g' % (ACC)
			print '================================'
			print '||   ||%6d |%6d |       ||' % (m.get_labels()[0],m.get_labels()[1])
			print '================================'
			print '||%3d||%6g |%6g |%6g ||' % (m.get_labels()[0],confusionmatrix[0,0],confusionmatrix[0,1],pos)#confusionmatrix[0,0]+confusionmatrix[0,1])
			print '||%3d||%6g |%6g |%6g ||' % (m.get_labels()[1],confusionmatrix[1,0],confusionmatrix[1,1],neg)#confusionmatrix[1,0]+confusionmatrix[1,1])
			print '||----------------------------||'
			print '||   ||%6g |%6g |%6g ||' % (confusionmatrix[0,0]+confusionmatrix[1,0],confusionmatrix[0,1]+confusionmatrix[1,1],pos+neg)#confusionmatrix[1,0]+confusionmatrix[1,1])
			print '================================'

		
		if outputlog != '':
			fout = open(outputlog,'a')
			print >> fout, results#[:-1]
#			for key in results[-1].keys():
#				print >> fout, key, results[-1][key]
			fout.close()
	
	pdfpages.close()

if __name__ == '__main__':
	main(sys.argv[1:])
